using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

namespace MetaView.Core;

/// <summary>
/// 周期包适配
/// </summary>
public class PeriodPackageAdapter : SingleStreamDataHandlingAdapter
{
    private readonly ConcurrentQueue<ValueByteBlock> m_bytes = new ConcurrentQueue<ValueByteBlock>();
    private long m_fireCount;
    private int m_dataCount;

    /// <inheritdoc/>
    protected override Task PreviewReceivedAsync(ByteBlock byteBlock)
    {
        var dataLength = byteBlock.Length;
        var valueByteBlock = new ValueByteBlock(dataLength);
        valueByteBlock.Write(byteBlock.Span);
        this.m_bytes.Enqueue(valueByteBlock);
        Interlocked.Increment(ref this.m_fireCount);
        Interlocked.Add(ref this.m_dataCount, dataLength);

        this.ThrowIfMoreThanMaxPackageSize(this.m_dataCount);

        _ = EasyTask.SafeRun(this.DelayGo);
        return EasyTask.CompletedTask;
    }

    private async Task DelayGo()
    {
        await Task.Delay(this.CacheTimeout).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
        if (Interlocked.Decrement(ref this.m_fireCount) == 0)
        {
            using (var byteBlock = new ByteBlock(this.m_dataCount))
            {
                while (this.m_bytes.TryDequeue(out var valueByteBlock))
                {
                    using (valueByteBlock)
                    {
                        byteBlock.Write(valueByteBlock.Span);
                        Interlocked.Add(ref this.m_dataCount, -valueByteBlock.Length);
                    }
                }

                byteBlock.SeekToStart();

                try
                {
                    await this.GoReceivedAsync(byteBlock, default).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
                }
                catch (Exception ex)
                {
                    this.OnError(ex, ex.Message, true, true);
                }
            }
        }
    }
}